home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / unix / sgmlc / modmd2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-03  |  31.7 KB  |  771 lines

  1. /******************************************************************************/
  2. /* MDENTITY: Fixed bug -- pne was not being stored in ecb->etx.n. */
  3. /* MDEXTID:  Fixed bug -- specified att list was not stored permanently. */
  4. /* MDEXTID:  Fixed bug -- default att list was not stored with entity. */
  5. /******************************************************************************/
  6. /* MDENTITY & MDEXTID: Support N/C/SDATA entities with attributes. */
  7. /* Changed free() to frem() to move memory allocation to TP environment. */
  8. /* Some minor LINT fixes. */
  9. /******************************************************************************/
  10. #include "sgmlincl.h"         /* #INCLUDE statements for SGML parser. */
  11. /******************************************************************************/
  12. /* MDENTITY: Process ENTITY declaration.
  13. */
  14. void mdentity(
  15. UNCH *tbuf)                   /* Work area for tokenization[LITLEN+2]. */
  16. {
  17.      struct fpi fpicb;        /* Formal public identifier structure. */
  18.      struct fpi *fpis = &fpicb;  /* Ptr to current or #DEFAULT fpi. */
  19.      UNCH ename[NAMELEN+3];   /* Entity name (+1 for RNI). */
  20.      UNCH pname[NAMELEN+2];   /* Parameter entity name (no PERO). */
  21.      UNCH *xnmpt = ename;     /* Ptr to name to use for MDEXTID. */
  22.      union etext etx;         /* Ptr to entity text. */
  23.      UNCH estore = ESM;       /* Entity storage class. */
  24.      struct entity *ecb;      /* Ptr to entity control block. */
  25.      int parmsw = 0;          /* 1=parameter entity declaration; 0 = not. */
  26.      int defltsw = 0;         /* 1=#DEFAULT declaration; 0=not. */
  27.      int dupsw = 0;           /* 1=duplicate entity (ignore); 0=not. */
  28.      PNE pne;                 /* Ptr to N/C/SDATA entity control block. */
  29.  
  30.      mdname = syn.k.entitee;  /* Declaration name for messages. */
  31.      subdcl = NULL;           /* No subject as yet. */
  32.      parmno = 0;              /* No parameters as yet. */
  33.      mdessv = es;             /* Save es for checking entity nesting. */
  34.      /* PARAMETER 1: Entity name.
  35.      */
  36.      pcbmd.newstate = 0;
  37.      parsemd(ename, ENTCASE, &pcblitp, NAMELEN);
  38. #ifndef FINAL
  39.      if (dtrace) tracemd("1: entity nm");
  40. #endif
  41.      switch (pcbmd.action) {
  42.      case PEN:
  43.           parsemd(pname, ENTCASE, &pcblitp, NAMELEN-1);
  44.           if (pcbmd.action!=NAS) {mderr(120, NULL, NULL); return;}
  45.           *ename = *pname+1;            /* Increment length for PERO. */
  46.           ename[1] = lex.d.pero;        /* Prefix PERO to name. */
  47.           memcpy(&ename[2]  , &pname[1],*pname-1  );  /* Copy to name buffer. */
  48.           parmsw = 1;                   /* Indicate parameter entity. */
  49.      case NAS:
  50.           break;
  51.      case RNS:           /* Reserved name started. */
  52.           if (strcmp(ename+1, syn.k.kdefault)) {
  53.                mderr(118, ename+1, syn.k.kdefault);
  54.                return;
  55.           }
  56.           memcpy(ename, indefent, *indefent);/* Copy #DEFAULT to name buffer. */
  57.           fpis = &fpidf;                /* Use #DEFAULT fpi if external. */
  58.           defltsw = 1;                  /* Indicate #DEFAULT is being defined.*/
  59.           break;
  60.      default:
  61.           mderr(122, NULL, NULL);
  62.           return;
  63.      }
  64.      subdcl = ename+1;                  /* Subject name for error messages. */
  65.      if ((ecb = entfind(ename))!=0 && ecb->estore) {
  66.           if (sw.swdupent) mderr(68, ename+1, NULL);
  67.           dupsw = 1;                    /* Not an error: finish parsing dcl. */
  68.      }
  69.      /* PARAMETER 2: Entity text keyword (optional).
  70.      */
  71.      pcbmd.newstate = 0;
  72.      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
  73. #ifndef FINAL
  74.      if (dtrace) tracemd("2: keyword");
  75. #endif
  76.      switch (pcbmd.action) {
  77.      case NAS:
  78.           if ((estore = (char)mapsrch(enttab, tbuf+1))==0) {
  79.                if (parmsw) {estore = ESP; xnmpt = pname;}
  80.                else estore = ESF;            /* Assume general entity. */
  81.                pne = (PNE)rmalloc(NESZ);
  82.                if (mdextid(tbuf, fpis, xnmpt, &estore, pne)==0) return;
  83.                if (defltsw) etx.x = NULL;
  84.                else if ((etx.x = entgen(&fpicb))==0) return;
  85.                goto parm4;
  86.           }
  87.           if (parmsw && (estore==ESX || estore==ESC)) {
  88.                mderr(38, tbuf+1, NULL);
  89.                estore = ESM;
  90.           }
  91.           pcbmd.newstate = 0;
  92.           parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
  93.           break;
  94.      default:
  95.           estore = ESM;
  96.           break;
  97.      }
  98.      /* PARAMETER 3: Parameter literal.
  99.      */
  100. #ifndef FINAL
  101.      if (dtrace) tracemd("3: literal");
  102. #endif
  103.      switch (pcbmd.action) {
  104.      case LITE:
  105.      case LIT:
  106.           switch (estore) {
  107.           case ESM:           /* LITERAL: parameter literal required. */
  108.           case ESC:           /* CDATA: parameter literal required. */
  109.           case ESX:           /* SDATA: parameter literal required. */
  110.           case ESI:           /* PI: parameter literal required. */
  111.                etx.c = strlsave(tbuf);
  112.                break;
  113.           case ESMD:          /* MD: parameter literal required. */
  114.                etx.c = sandwich(tbuf, lex.m.mdo, lex.m.mdc);
  115.                break;
  116.           case ESMS:          /* MS: parameter literal required. */
  117.                etx.c = sandwich(tbuf, lex.m.mss, lex.m.mse);
  118.                break;
  119.           case ESS:           /* STARTTAG: parameter literal required. */
  120.                tagtext(tbuf, &estore, lex.m.lennst, lex.m.stag, &etx);
  121.                break;
  122.           case ESE:           /* ENDTAG: parameter literal required. */
  123.                tagtext(tbuf, &estore, lex.m.lennet, lex.m.etag, &etx);
  124.                break;
  125.           }
  126.           break;
  127.      default:
  128.           mderr(123, NULL, NULL);
  129.           return;
  130.      }
  131.      /* PARAMETER 4: End of declaration.
  132.      */
  133.      pcbmd.newstate = 0;
  134.      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
  135.      parm4:
  136. #ifndef FINAL
  137.      if (dtrace) tracemd(emd);
  138. #endif
  139.      if (pcbmd.action!=EMD) mderr(126, NULL, NULL);
  140.      if (es!=mdessv) synerr(37, &pcbmd);
  141.  
  142.      /* EXECUTE: If the entity already exists, ignore the new definition.
  143.                  If it is a new entity, store the definition.
  144.      */
  145.      if (dupsw) {
  146.           if (estore<ESFM && estore!=ESS && estore!=ESE) frem(etx.c);
  147.           return;
  148.      }
  149.      ++ds.ecbcnt;                       /* Do capacity before NOTATION. */
  150.      ds.ecbtext +=
  151.           (estore<ESFM && estore!=ESS && estore!=ESE) ? (int)*etx.c-2 : entlen;
  152.      ecb = entdef(ename, estore, &etx); /* Define the entity. */
  153.      if (estore==ESN) {                 /* If entity is external: */
  154.           NEENAME(pne) = ecb->ename;    /* Store entity name in ne. */
  155.           NEID(pne) = etx.x;            /* Store system fileid in ne. */
  156.           ecb->etx.n = pne;             /* Store ne control block in etx. */
  157. #ifndef FINAL
  158.           if (etrace || atrace || ntrace) traceesn(pne);
  159. #endif
  160.      }
  161.      if (defltsw) ecbdeflt = ecb;                    /* If #DEFAULT save ecb. */
  162. }
  163. /******************************************************************************/
  164. /* TAGTEXT: Generate entity text for STARTTAG or ENDTAG.
  165. */
  166. VOID tagtext(
  167. UNCH *tbuf,                   /* Entity text as specified in declaration. */
  168. UNCH *pestore,                /* Point to caller's estore value. */
  169. int lennt,                    /* Length of a null tag (start- or end-). */
  170. UNCH *marktag,                /* Tag open delimiter (stago or etago). */
  171. union etext *petext)          /* Pointer to etext union. */
  172. {
  173.      if ((entlen = *tbuf-2 + lennt)==lennt)  /* Null tag: no etd. */
  174.           {petext->e = ETDNULL; return;}
  175.      if (!parseval(tbuf, ANAME, lbuf))       /* GI with no atts: use etd. */
  176.           {petext->e = etddef(pvalptr); return;}
  177.      *pestore = EST;                         /* GI with atts: use tag. */
  178.           petext->c = sandwich(tbuf, marktag, lex.m.tagc);
  179. }
  180. /******************************************************************************/
  181. /* ENTFIX: Change a type ESS or ESE entity to the corresponding tag form.
  182.            The entity is assumed to exist.
  183. */
  184. VOID entfix(
  185. UNCH *ename)                  /* Entity name (with length and EOS). */
  186. {
  187.      struct entity *ecb;      /* Entity control block. */
  188.  
  189.      /* Get the entity control block, as the entity has been defined. */
  190.      ecb = entfind(ename);
  191.      ecb->etx.c = sandwich(ecb->etx.e->etdgi,
  192.                            ecb->estore==ESS ? lex.m.stag : lex.m.etag, lex.m.tagc);
  193.      ecb->estore = EST;
  194. #ifndef FINAL
  195.      if (etrace) traceecb("ENTFIX", ecb);
  196. #endif
  197. }
  198. /******************************************************************************/
  199. /* MDEXTID: Process external identifier parameter of a markup declaration.
  200.             On entry, tbuf contains SYSTEM or PUBLIC if all is well.
  201.             NULL is returned if an error, otherwise fpis.  If it is a
  202.             valid external data entity, the caller's estore is set to ESN
  203.             and its nxetype is set to the code for the external entity type.
  204.             The event that terminated the parse is preserved in pcb.action,
  205.             so the caller should process it before further parsing.
  206. */
  207. struct fpi *mdextid(
  208. UNCH *tbuf,                   /* Work area for tokenization[2*(LITLEN+2)]. */
  209. struct fpi *fpis,             /* FPI structure. */
  210. UNCH *ename,                  /* Entity or notation name, with length and EOS.*/
  211.                               /* NOTE: No PERO on parameter entity name. */
  212. UNCH *estore,                 /* DTD, general or parameter entity, DCN. */
  213. PNE pne)                      /* Caller's external entity ptr. */
  214. {
  215.      PDCB dcb;                /* Ptr to DCN control block. */
  216.      int exidtype;            /* External ID type: 0=none 1=system 2=public. */
  217.      int exetype;             /* External entity type. */
  218.  
  219.      memset((UNIV)fpis, 0, (UNS)FPISZ);     /* Initialize fpi structure. */
  220.      /* Move entity name into fpi (any PERO was stripped by caller). */
  221.      memcpy(fpis->fpinm, ename, (UNS)(fpis->fpinml = *ename));
  222.      entlen = 0;              /* Initialize external ID length. */
  223.  
  224.      /* PARAMETER 1: External identifier keyword or error.
  225.      */
  226. #ifndef FINAL
  227.      if (dtrace) tracemd("1: extid keyword");
  228. #endif
  229.      if ((exidtype = mapsrch(exttab, tbuf+1))==0) {
  230.           mderr(29, NULL, NULL);
  231.           return (struct fpi *)0;
  232.      }
  233.      if (exidtype==EDSYSTEM) goto parm3;
  234.  
  235.      /* PARAMETER 2: Public ID literal.
  236.      */
  237.      pcbmd.newstate = 0;
  238.      parsemd(fpis->fpipubis, NAMECASE, &pcblitv, LITLEN);
  239. #ifndef FINAL
  240.      if (dtrace) tracemd("2: pub ID literal");
  241. #endif
  242.      switch (pcbmd.action) {
  243.      case LITE:               /* Use alternative literal delimiter. */
  244.      case LIT:                /* Save literal as public ID string. */
  245.           entlen = (fpis->fpipubl = *fpis->fpipubis) - 2;
  246.           break;
  247.      default:
  248.           mderr(117, NULL, NULL);
  249.           return (struct fpi *)0;        /* Signal error to caller. */
  250.      }
  251.      /* PARAMETER 3: System ID literal.
  252.      */
  253.      parm3:
  254.      pcbmd.newstate = 0;
  255.      parsemd(fpis->fpisysis, NAMECASE, &pcblitc, LITLEN);
  256. #ifndef FINAL
  257.      if (dtrace) tracemd("3: sys ID literal");
  258. #endif
  259.      if (pcbmd.action==LIT || pcbmd.action==LITE) {
  260.           entlen += (fpis->fpisysl = *fpis->fpisysis) - 2;
  261.           pcbmd.newstate = 0;
  262.           parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
  263.      }
  264.      else memcpy(tbuf  , fpis->fpisysis, *fpis->fpisysis );
  265.      if (*estore!=ESF || pcbmd.action!=NAS) goto genfpi;
  266.  
  267.      /* PARAMETER 4: Entity type keyword.
  268.      */
  269. #ifndef FINAL
  270.      if (dtrace) tracemd("4: Entity type");
  271. #endif
  272.      if ((exetype = mapsrch(extettab, tbuf+1))==0) {
  273.           mderr(24, tbuf+1, NULL);
  274.           return (struct fpi *)0;
  275.      }
  276.      if (exetype==ESNSUB) {
  277.           mderr(90, tbuf+1, NULL);
  278.           return (struct fpi *)0;
  279.      }
  280.      NEXTYPE(pne) = (char)exetype; /* Save entity type in caller's ne. */
  281.      *estore = ESN;                /* Signal that entity is a data entity. */
  282.  
  283.      /* PARAMETER 5: Notation name.
  284.      */
  285.      pcbmd.newstate = 0;
  286.      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
  287. #ifndef FINAL
  288.      if (dtrace) tracemd("5: notation");
  289. #endif
  290.      if (pcbmd.action!=NAS) {mderr(119, tbuf+1, NULL); return (struct fpi *)0;}
  291.      /* Locate the data content notation. */
  292.      pne->nedcn = dcb = dcndef(lbuf);
  293.  
  294.      /* PARAMETER 6: Data attribute specification.
  295.      */
  296.      pcbmd.newstate = 0;
  297.      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
  298. #ifndef FINAL
  299.      if (dtrace) tracemd("6: [att list]");
  300. #endif
  301.      if (pcbmd.action!=MDS) {     /* No attributes specified. */
  302.           NEAL(pne) = dcb->adl;   /* Copy default atts (if any). */
  303.           goto genfpi;
  304.      }
  305.      if (dcb->adl==0) {            /* Atts specified, but none defined. */
  306.           mderr(22, NULL, NULL);
  307.           return (struct fpi *)0;
  308.      }
  309.      pcbstag.newstate = pcbstan;   /* First separator is optional. */
  310.      if ((parseatt(dcb->adl, tbuf, lbuf))==0)/* Empty list. */
  311.           mderr(91, NULL, NULL);
  312.      else {
  313.           adlval((int)ADN, (struct etd *)0);
  314.           NEAL(pne) = (struct ad *)rmalloc((1+ADN)*ADSZ);
  315.           memcpy((UNIV)NEAL(pne), (UNIV)al, (1+ADN)*ADSZ );
  316.           ds.attcnt += AN;         /* Number of attributes defined. */
  317.           ds.attgcnt += ADN - AN;  /* Number of att grp members. */
  318.      }
  319.      parse(&pcbmds);               /* Parse the list ending. */
  320.      pcbmd.newstate = 0;           /* Parse next token for caller. */
  321.      parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
  322.  
  323.      /* GENFPI: Builds a formal public identifier structure, including the
  324.                 entity name, offsets of the components of the public ID, and
  325.                 other data a system might use to identify the actual file.
  326.      */
  327.      genfpi:
  328. #ifndef FINAL
  329.      if (dtrace) tracemd("7: generate fpi");
  330. #endif
  331.      fpis->fpistore = *estore - ESFM + 1;    /* External entity type: 1-6. */
  332.      /* Analyze public ID and make structure entries. */
  333.      if (exidtype==EDPUBLIC && parsefpi(fpis)>0) {
  334.           mderr(88, fpis->fpipubis+1, NULL);
  335.           fpis->fpiversw = -1;               /* Signal bad formal public ID. */
  336.      }
  337.      return (fpis);
  338. }
  339. /******************************************************************************/
  340. /* PARSEFPI: Parses a formal public identifier and builds a control block.
  341.              PARSEFPI returns a positive error code (1-9), or 0 if no errors.
  342.              It set fpiversw if no version was specified in the ID and the
  343.              public text is in a class that permits display versions.
  344.              Note: An empty version ("//") can be specified (usually it is
  345.              the non-device-specific form, such as a definitional entity set).
  346. */
  347. int parsefpi(
  348. PFPI f)                       /* Ptr to formal public identifier structure. */
  349. {
  350.      UNCH *l;                 /* Pointer to EOS of public identifier. */
  351.      UNCH *p, *q;             /* Ptrs to current field in public identifier. */
  352.  
  353.      p = f->fpipubis;                   /* Point to start of identifier. */
  354.      l = *p + p++ -1;                   /* Point to EOS of identifier. */
  355.      if (*p=='+' || *p=='-') {          /* If owner registered, unregistered. */
  356.           f->fpiot = *p;                /* Save owner type. */
  357.           if ((p += 3)>=l) return 1;    /* Get to owner ID field. */
  358.      }
  359.      else f->fpiot = '!';               /* Indicate ISO owner identifier. */
  360.      if ((q = pubfield(p, l, '/'))==0)  /* Find end of owner ID field. */
  361.           return 2;
  362.      f->fpiol = (char)pifldlen;         /* Save owner ID length. */
  363.      f->fpio = (int)(p - f->fpipubis);  /* Save offset in pubis to owner ID. */
  364.  
  365.      if ((p = pubfield(q, l, ' '))==0)  /* Find end of text class field. */
  366.           return 3;
  367.      *(--p) = EOS;                      /* Temporarily make class a string. */
  368.      f->fpic = mapsrch(pubcltab, q);    /* Check for valid uc class name.*/
  369.      *p++ = ' ';                        /* Restore the SPACE delimiter. */
  370.      if (f->fpic==0) return 4;          /* Error if not valid uc class name.*/
  371.  
  372.      if (*p=='-') {                     /* If text is unavailable public text.*/
  373.           f->fpitt = *p;                /* Save text type. */
  374.           if ((p += 3)>=l) return 5;    /* Get to text description field. */
  375.      }
  376.      else f->fpitt = '+';               /* Indicate available public text. */
  377.      if ((q = pubfield(p, l, '/'))==0)  /* Find end of text description. */
  378.           return 6;
  379.      f->fpitl = (char)pifldlen;         /* Save text description length. */
  380.      f->fpit = (int)(p - f->fpipubis);  /* Save ptr (in pubis) to description.*/
  381.  
  382.      p = pubfield(q, l, '/');           /* Bound language field. */
  383.      if (pifldlen!=2) return 7;         /* Language must be 2 characters. */
  384.      f->fpil[0] = *q;                   /* Save 1st language character. */
  385.      f->fpil[1] = *(q+1);               /* Save 2nd language character. */
  386.  
  387.      if (p!=0) {                        /* If there is a version field: */
  388.           if (f->fpic<FPICMINV)         /* Error if class prohibits versions. */
  389.                return 8;
  390.           if ((pubfield(p, l, '/'))!=0) /* Bound version field. */
  391.                return 9;                /* Error if yet another field. */
  392.           f->fpivl = (char)pifldlen;    /* Save version length. */
  393.           f->fpiv = (int)(p-f->fpipubis); /* Save ptr (in pubis) to version. */
  394.      }
  395.      else if (f->fpic>=FPICMINV) f->fpiversw = 1;/* No version: get the best. */
  396.      return(0);
  397. }
  398. /******************************************************************************/
  399. /* PUBFIELD: Returns ptr to next field, or NULL if ID has ended.
  400. */
  401. UNCH *pubfield(
  402. UNCH *p,                      /* Public identifier field (no length or EOS). */
  403. UNCH *l,                      /* Pointer to EOS of public identifier. */
  404. UNCH d)                       /* Field delimiter: ' ' or '/'. */
  405. {
  406.      UNCH *psv = p+1;         /* Save starting value of p. */
  407.  
  408.      while (p<l) {
  409.           if (*p++==d) {              /* Test for delimiter character. */
  410.                pifldlen =(UNS)(p-psv);/* Save field length (no len or EOS). */
  411.                if (d=='/' && *p++!=d) /* Solidus requires a second one. */
  412.                     continue;
  413.                return(p);             /* Return ptr to next field. */
  414.           }
  415.      }
  416.      pifldlen =(UNS)(p - --psv);      /* Save field length (no len or EOS). */
  417.      return NULL;
  418. }
  419. /******************************************************************************/
  420. /* MDMS: Process marked section start.
  421.          If already in special parse, bump the level counters and return
  422.          without parsing the declaration.
  423. */
  424. struct parse *mdms(
  425. UNCH *tbuf,                   /* Work area for tokenization [NAMELEN+2]. */
  426. struct parse *pcb)            /* Parse control block for this parse. */
  427. {
  428.      int key;                 /* Index of keyword in mslist. */
  429.      int ptype;               /* Parameter token type. */
  430.      int pcbcode = 0;         /* Parse code: 0=same; 2-4 per defines. */
  431.  
  432.      if (++mslevel>TAGLVL) {
  433.           --mslevel;
  434.           sgmlerr(27, (struct parse *)0, ntoa(TAGLVL), NULL);
  435.      }
  436.  
  437.      /* If already in IGNORE mode, return without parsing parameters. */
  438.           if (msplevel) {++msplevel; return(pcb);}
  439.  
  440.      parmno = 0;                   /* No parameters as yet. */
  441.      mdessv = es;                  /* Save es for checking entity nesting. */
  442.      pcbmd.newstate = pcbmdtk;     /* First separator is optional. */
  443.  
  444.      /* PARAMETERS: TEMP, RCDATA, CDATA, IGNORE, INCLUDE, or MDS. */
  445.      while ((ptype = parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN))==NAS){
  446.           if ((key = mapsrch(mstab, tbuf+1))==0) {
  447.                sgmlerr(64, (struct parse *)0, ntoa(parmno), tbuf+1);
  448.                continue;
  449.           }
  450.           if (key==MSTEMP) continue;       /* TEMP: for documentation. */
  451.           msplevel = 1;                    /* Special parse required. */
  452.           if (key>pcbcode) pcbcode = key;  /* Update if higher priority. */
  453.      }
  454.      if (ptype!=MDS) {
  455.           NEWCC;                           /* Syntax error did REPEATCC. */
  456.           sgmlerr(97, (struct parse *)0, lex.m.dso, NULL);
  457.           REPEATCC;                        /* 1st char of marked section. */
  458.      }
  459.      if (es!=mdessv) synerr(37, pcb);
  460. #ifndef FINAL
  461.      if (mtrace) tracems(1, pcbcode, mslevel, msplevel);
  462. #endif
  463.      if (pcbcode==MSIGNORE) pcb = &pcbmsi;
  464.      else if (pcbcode) {
  465.           pcb = pcbcode==MSCDATA  ? &pcbmsc : (rcessv = es, &pcbmsrc);
  466.      }
  467.      return(pcb);              /* Tell caller whether to change the parse. */
  468. }
  469. /******************************************************************************/
  470. /* MDMSE: Process marked section end.
  471.           Issue an error if no marked section had started.
  472. */
  473. int mdmse(void)
  474. {
  475.      int retcode = 0;         /* Return code: 0=same parse; 1=cancel special. */
  476.  
  477.      if (mslevel) --mslevel;
  478.      else sgmlerr(26, (struct parse *)0, NULL, NULL);
  479.  
  480.      if (msplevel) if (--msplevel==0) retcode = 1;
  481. #ifndef FINAL
  482.      if (mtrace) tracems(0, retcode, mslevel, msplevel);
  483. #endif
  484.      return retcode;
  485. }
  486. /******************************************************************************/
  487. /* MDNOT: Process NOTATION declaration.
  488. */
  489. VOID mdnot(
  490. UNCH *tbuf)                   /* Work area for tokenization[LITLEN+2]. */
  491. {
  492.      struct fpi fpicb;        /* Formal public identifier structure. */
  493.      PDCB dcb;                /* Ptr to notation entity in dcntab. */
  494.      UNIV ntx;                /* Ptr to notation text (DOS identifier). */
  495.      UNCH estore = ESK;       /* Entity storage class. */
  496.  
  497.      mdname = syn.k.notation; /* Identify declaration for messages. */
  498.      subdcl = NULL;           /* No subject as yet. */
  499.      parmno = 0;              /* No parameters as yet. */
  500.      mdessv = es;             /* Save es for checking entity nesting. */
  501.  
  502.      /* PARAMETER 1: Notation name.
  503.      */
  504.      pcbmd.newstate = 0;
  505.      parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
  506. #ifndef FINAL
  507.      if (dtrace) tracemd("1: name");
  508. #endif
  509.      if (pcbmd.action!=NAS) {mderr(120, NULL, NULL); return;}
  510.      subdcl = lbuf+1;         /* Save notation name for error msgs. */
  511.  
  512.      /* PARAMETER 2: External identifier keyword.
  513.      */
  514.      pcbmd.newstate = 0;
  515.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  516. #ifndef FINAL
  517.      if (dtrace) tracemd("2: extid");
  518. #endif
  519.      if (pcbmd.action!=NAS) {mderr(29, NULL, NULL); return;}
  520.      if (mdextid(tbuf, &fpicb, lbuf, &estore, (PNE)0)==0) return;
  521.      if ((ntx = entgen(&fpicb))==0) return;
  522.  
  523.      /* PARAMETER 3: End of declaration.
  524.                      Token was parsed by MDEXTID.
  525.      */
  526. #ifndef FINAL
  527.      if (dtrace) tracemd(emd);
  528. #endif
  529.      if (pcbmd.action!=EMD) mderr(126, NULL, NULL);
  530.      if (es!=mdessv) synerr(37, &pcbmd);
  531.  
  532.      /* EXECUTE: Store notation name.
  533.                  If defined with dcnid!=0, ignore this duplicate assignment.
  534.                  Else if dcnid==0, assign ntx to dcnid.
  535.                  If not defined at all, do a complete definition.
  536.      */
  537.      if ( (dcb = dcnfind(lbuf))!=0 && dcb->dcnid!=0 )
  538.           {mderr(56, lbuf+1, NULL); return;}
  539.      /* else */
  540.      (dcb = dcndef(lbuf))->dcnid = ntx;
  541.      ++ds.dcncnt; ds.dcntext += entlen;
  542. #ifndef FINAL
  543.      if (ntrace) tracedcn(dcb);
  544. #endif
  545.      return;
  546. }
  547. /******************************************************************************/
  548. /* DCNDEF: Define a notation and return its DCNCB.
  549.            If caller does not care if it already exists,
  550.            he should specify NULL for the notation text
  551.            so we don't clobber the existing text (if any).
  552. */
  553. struct dcncb *dcndef(
  554. UNCH *nname)                  /* Notation name (with length and EOS). */
  555. {
  556.      return((PDCB)hin((THASH)dcntab, nname, 0, DCBSZ));
  557. }
  558. /******************************************************************************/
  559. /* DCNFIND: If a notation was declared, return its DCNCB.
  560.             Return NULL if it is not defined.
  561. */
  562. struct dcncb *dcnfind(
  563. UNCH *nname)                  /* Notation name (with length and EOS). */
  564. {
  565.      return((PDCB)hfind((THASH)dcntab, nname, 0));
  566. }
  567. /******************************************************************************/
  568. #define SRM(i) (srhptr->srhsrm[i]) /* Current entry in SHORTREF map. */
  569. /******************************************************************************/
  570. /* MDSRMDEF: Process short reference mapping declaration.
  571. */
  572. VOID mdsrmdef(
  573. UNCH *tbuf)                   /* Work area for tokenization[LITLEN+2]. */
  574. {
  575.      UNCH sname[NAMELEN+2];   /* Name of short reference map being defined. */
  576.      struct entity *entcb;    /* Ptr to defined entity. */
  577.      PSRH srhptr;             /* Ptr to short reference map hdr (in srhtab).*/
  578.      int srn;                 /* Short reference delimiter number in srdeltab.*/
  579.  
  580.      mdname = syn.k.shortref; /* Identify declaration for messages. */
  581.      subdcl = NULL;           /* No subject as yet. */
  582.      parmno = 0;              /* No parameters as yet. */
  583.      mdessv = es;             /* Save es for checking entity nesting. */
  584.      /* PARAMETER 1: SHORTREF map name.
  585.      */
  586.      pcbmd.newstate = 0;
  587.      parsemd(sname, NAMECASE, &pcblitp, NAMELEN);
  588. #ifndef FINAL
  589.      if (dtrace) tracemd("1: map nm");
  590. #endif
  591.      if (pcbmd.action!=NAS) {mderr(120, NULL, NULL); return;}
  592.      if ((srhptr = srhfind(sname))!=0) {
  593.           /* Error if map was declared (not just used). */
  594.           if (SRM(0)) {mderr(56, sname+1, NULL); return;}
  595.      }
  596.      else srhptr = srhdef(sname);  /* Create map with SRs mapped to NULL.*/
  597.      SRM(0) = (PECB)srhptr;        /* Indicate map was actually declared.*/
  598.      subdcl = sname+1;             /* Save map name for error msgs. */
  599.  
  600.      while ( pcbmd.newstate = 0,
  601.              parsemd(tbuf, NAMECASE, &pcblitp, SRMAXLEN)==LIT
  602.           || pcbmd.action==LITE ) {
  603.           /* PARAMETER 2: Delimiter string.
  604.           */
  605. #ifndef FINAL
  606.           if (dtrace) tracemd("2: SR string");
  607. #endif
  608.           if ((srn = mapsrch(lex.s.dtb, tbuf+1))==0) {
  609.                mderr(124, tbuf+1, NULL);
  610.                goto cleanup;
  611.           }
  612.           /* PARAMETER 3: Entity name.
  613.           */
  614.           pcbmd.newstate = 0;
  615.           parsemd(tbuf, ENTCASE, &pcblitp, NAMELEN);
  616. #ifndef FINAL
  617.           if (dtrace) tracemd("3: entity");
  618. #endif
  619.           if (pcbmd.action!=NAS) {mderr(120, NULL, NULL); goto cleanup;}
  620.           if ((entcb = entfind(tbuf))==0)
  621.                entcb = entdef(tbuf, '\0', (union etext *)NULL);
  622.           if (SRM(srn)) {
  623.                mderr(56, (srn<lex.s.prtmin ? lex.s.pdtb[srn]
  624.                                        : lex.s.dtb[srn].mapnm), NULL);
  625.                continue;
  626.           }
  627.           SRM(srn) = entcb;
  628.           if (srn>=lex.s.fce && srn!=lex.s.hyp && srn!=lex.s.hyp2)
  629.                lexcnm[*lex.s.dtb[srn].mapnm] = lex.l.fce;
  630.           else if (srn==lex.s.spc) lexcnm[' '] = lex.l.spcr;
  631.      }
  632.      /* PARAMETER 4: End of declaration.
  633.      */
  634. #ifndef FINAL
  635.      if (dtrace) tracemd(emd);
  636. #endif
  637.      if (parmno==2)
  638.           {mderr((UNS)(pcbmd.action==EMD ? 28:123), NULL, NULL); goto cleanup;}
  639.      if (pcbmd.action!=EMD) mderr(126, NULL, NULL);
  640.      if (es!=mdessv) synerr(37, &pcbmd);
  641.      ++ds.srcnt;
  642. #ifndef FINAL
  643.      if (etrace) tracesrm("SHORTREF", srhptr->srhsrm, NULL);
  644. #endif
  645.      return;
  646.  
  647.      /* CLEANUP: Free map storage if no valid mappings. */
  648.      cleanup:
  649.           frem((UNIV)srhptr->srhsrm);
  650.           hout((THASH)srhtab, sname, 0);
  651. }
  652. /******************************************************************************/
  653. /* MDSRMUSE: Activate a short reference map.
  654. */
  655. VOID mdsrmuse(
  656. UNCH *tbuf)                   /* Work area for tokenization[LITLEN+2]. */
  657. {
  658.      PSRH srhptr;             /* Ptr to short reference map hdr (in srhtab).*/
  659.      TECB srmptr;             /* Ptr to short reference map (in header). */
  660.      PETD nmgrp[GRPCNT+1];    /* Array of etds being defined. */
  661.      int i;                   /* Loop counter; temporary variable. */
  662.      UNCH sname[NAMELEN+2];   /* Save area for name of undefined map. */
  663.  
  664.      mdname = syn.k.usemap;   /* Identify declaration for messages. */
  665.      subdcl = NULL;           /* No subject as yet. */
  666.      parmno = 0;              /* No parameters as yet. */
  667.      mdessv = es;             /* Save es for checking entity nesting. */
  668.      /* PARAMETER 1: SHORTREF map name or "#EMPTY".
  669.      */
  670.      pcbmd.newstate = 0;
  671.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  672. #ifndef FINAL
  673.      if (dtrace) tracemd("1: map nm");
  674. #endif
  675.      switch (pcbmd.action) {
  676.      case RNS:                /* Empty SHORTREF map requested. */
  677.           if (strcmp(tbuf+1, syn.k.empty)) {
  678.                mderr(118, tbuf+1, syn.k.empty);
  679.                return;
  680.           }
  681.           srmptr = SRMNULL;
  682.           subdcl = syn.k.empty; /* Subject name for error messages. */
  683.           break;
  684.      case NAS:                /* Map name specified; save if undefined. */
  685.           subdcl = tbuf+1;    /* Subject name for error messages. */
  686.           if ((srhptr = srhfind(tbuf))==0) {
  687.                if (!indtdsw) {mderr(125, NULL, NULL); return;}
  688.                /* else */ memcpy(sname , tbuf, (UNS)sizeof(sname));
  689.           }
  690.           else srmptr = srhptr->srhsrm;
  691.           break;
  692.      default:
  693.           mderr(120, NULL, NULL);
  694.           return;
  695.      }
  696.      /* PARAMETER 2: Element name or a group of them. (In DTD only.)
  697.      */
  698.      pcbmd.newstate = 0;
  699.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  700. #ifndef FINAL
  701.      if (dtrace) tracemd("2: GI or grp");
  702. #endif
  703.      if (pcbmd.action!=EMD && !indtdsw) {mderr(28, NULL, NULL); return;}
  704.      switch (pcbmd.action) {
  705.      case NAS:
  706.           nmgrp[0] = etddef(tbuf);
  707.           nmgrp[1] = (PETD)NULL;
  708.           break;
  709.      case GRPS:
  710.           parsegrp(nmgrp, &pcbgrnm);
  711.           break;
  712.      case EMD:
  713.           tags[ts].tsrm = srmptr;
  714. #ifndef FINAL
  715.      if (etrace) tracesrm("USEMAP", tags[ts].tsrm, tags[ts].tetd->etdgi+1);
  716. #endif
  717.           goto realemd;
  718.      default:
  719.           mderr(121, NULL, NULL);
  720.           return;
  721.      }
  722.      /* PARAMETER 3: End of declaration.
  723.      */
  724.      pcbmd.newstate = 0;
  725.      parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
  726. #ifndef FINAL
  727.      if (dtrace) tracemd(emd);
  728. #endif
  729.      if (pcbmd.action!=EMD) mderr(126, NULL, NULL);
  730.      /* If map has not yet been defined, do it and get map pointer. */
  731.      if (!srhptr) srmptr = (srhdef(sname))->srhsrm;
  732.  
  733.      /* Store the map pointer for each element name specified.
  734.      */
  735. #ifndef FINAL
  736.      if (gtrace) tracegrp(nmgrp);
  737. #endif
  738.      for (i = -1; nmgrp[++i];) {
  739.           if (!nmgrp[i]->etdsrm) nmgrp[i]->etdsrm = srmptr;
  740.           else if (sw.swdupent) mderr(68, nmgrp[i]->etdgi+1, NULL);
  741.      }
  742.      realemd:
  743.      if (es!=mdessv) synerr(37, &pcbmd);
  744. }
  745. /******************************************************************************/
  746. /* SRHDEF: Define a SHORTREF map and return ptr to its header.
  747.            All entries in map are mapped to NULL.
  748.            Caller must determine whether it already exists.
  749. */
  750. PSRH srhdef(
  751. UNCH *sname)                  /* SHORTREF map name (with length and EOS). */
  752. {
  753.      PSRH srh;                /* Ptr to SHORTREF map hdr in srhtab. */
  754.  
  755.      (srh = (PSRH)hin((THASH)srhtab, sname, 0, SRHSZ))->srhsrm =
  756.           (TECB)rmalloc((UNS)(lex.s.dtb[0].mapdata+1)*sizeof(PECB));
  757.      return(srh);
  758. }
  759. /******************************************************************************/
  760. /* SRHFIND: If a SHORTREF map was declared, return the ptr to its header.
  761.             Return NULL if it is not defined.
  762. */
  763. PSRH srhfind(
  764. UNCH *sname)                  /* SHORTREF map name (with length and EOS). */
  765. {
  766.      return((PSRH)hfind((THASH)srhtab, sname, 0));
  767. }
  768. /******************************************************************************/
  769. #undef SRM
  770. /******************************************************************************/
  771.